Skip to content

Fix FPs in bitwiseOnBoolean#3455

Merged
danmar merged 12 commits into
cppcheck-opensource:mainfrom
pfultz2:fp-bitwise-bool-non-const
Sep 19, 2021
Merged

Fix FPs in bitwiseOnBoolean#3455
danmar merged 12 commits into
cppcheck-opensource:mainfrom
pfultz2:fp-bitwise-bool-non-const

Conversation

@pfultz2
Copy link
Copy Markdown
Contributor

@pfultz2 pfultz2 commented Sep 9, 2021

We no longer warn on cases where logical operators are not equivalent to the bitwise version:

  • Because of short-circuiting a bitwise operator is necessary if there is side-effects and so can't be replaced
  • Replacing | with || when one operand is an integer produce different results so we shouldn't warn

I kept it inconclusive, but I think we can remove the inconclusive now. We could make the | with integer inconclusive because even though it isnt equivalent it could still be suspect(but maybe this is better in an addon).

@pfultz2
Copy link
Copy Markdown
Contributor Author

pfultz2 commented Sep 9, 2021

Actually, thinking about it more. I think we can warn for a | b where a is an integer, but we should change the message, because a | b is not equivalent to a || b, but equivalent to just a.

Comment thread test/testbool.cpp Outdated
" if(a | b) {}\n"
"}");
ASSERT_EQUALS(
"[test.cpp:2]: (style, inconclusive) Bitwise expression 'a|b' with boolean expression 'a' is equivalent to 'b'?\n",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this. maybe a is true and b is 0.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thats right, then let me remove the warning when using a|b.

@pfultz2
Copy link
Copy Markdown
Contributor Author

pfultz2 commented Sep 15, 2021

Anymore feedback?

Copy link
Copy Markdown
Collaborator

@danmar danmar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel I understand why we write these warnings. So your idea is that if lhs (or both lhs and rhs?) are const expressions then we should warn? Is the motivation for that to prevent bugs or to speedup?

In the true positive test cases the expressions are actually conditions. I can actually feel that the code if (a || b) does look better than if (a | b). For purely stylistic reasons. But this checker does not check if the expression is a condition. Should it?

Comment thread lib/checkbool.cpp Outdated
continue;
if (!isConstExpression(tok->astOperand1(), mSettings->library, true, mTokenizer->isCPP()))
continue;
if (!isConstExpression(tok->astOperand1(), mSettings->library, true, mTokenizer->isCPP()))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you intend to pass astOperand2 here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, good catch. I am surprised that duplicateCondition didnt catch this.

@pfultz2
Copy link
Copy Markdown
Contributor Author

pfultz2 commented Sep 16, 2021

So your idea is that if lhs (or both lhs and rhs?) are const expressions then we should warn? Is the motivation for that to prevent bugs or to speedup?

It is to improve clarity, which can help prevent bugs.

First, if we are going to suggest to use logical operators instead of bitwise operators, then we need to make sure this suggestion will do what the user intended. So if f() | g() have side effects then we definitely cannot suggest logical operators because it is quite possible the user intended for f() and g() to be executed regardless of what boolean is returned due to side effects.

Secondly, by making the intention of using | vs || if there is side effects explicit, then it could find bugs where the user intended for side effects but there was no actual side effects.

On the flip side we could consider suggesting bitwise operators when there is side effects, but I suspect there may be too many FPs from this as using logical operators can be intentional to avoid running a function with side effects based on previous conditions.

We can replace a & b with a && b when there is no side effects as the two are semantically equivalent. However, trying to suggest a & b instead of a && b when there is side effects is still not semantically equivalent so this can lead to FPs.

Should it?

For a | b it should probably check if the parent is a boolean or is coerced to a boolean. a | b and a || b does not produce the same result when only one operand is bool unless it is later converted to a bool(such as in an if statement or assigned to a boolean). I can add a check for if this is converted to a bool. Currently, I dont warn at all if only one operand is a bool.

@danmar
Copy link
Copy Markdown
Collaborator

danmar commented Sep 16, 2021

It is to improve clarity, which can help prevent bugs.

ok good.

I agree we need to check for side effects.

such as in an if statement or assigned to a boolean

I do like to use | sometimes when I assign to a boolean.

@pfultz2
Copy link
Copy Markdown
Contributor Author

pfultz2 commented Sep 18, 2021

I do like to use | sometimes when I assign to a boolean.

I dont really see the difference with assign to a bool or using in an if statement. It can still provide clarity using logical ops that there are no side effects.

@danmar
Copy link
Copy Markdown
Collaborator

danmar commented Sep 19, 2021

ok I guess this is a improvement at least however I still have the feeling it's too controversial.

@danmar danmar merged commit c76e634 into cppcheck-opensource:main Sep 19, 2021
@pfultz2 pfultz2 deleted the fp-bitwise-bool-non-const branch September 19, 2021 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants